package org.jetlinks.pro.assets.impl.terms;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.*;
import org.hswebframework.ezorm.core.param.Term;
import org.hswebframework.web.authorization.Dimension;
import org.jetlinks.pro.assets.DimensionInfo;
import org.jetlinks.pro.assets.impl.entity.DimensionAssetBindingEntity;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 维度资产条件,用于查询和维度关联的资产信息
 * <pre>
 * {
 * "column":"id", //资产主键列名
 * "termType": "dim-assets", //固定
 * "value":{
 *      "not":false,
 *      "assetType":"device", //资产类型
 *      "targets":[{"type":"org","id":"orgId"}], //关联维度
 *      "relations":["owner"] //资产关系
 *   }
 * }
 * </pre>
 *
 * @author zhouhao
 * @since 1.11
 */
@Getter
@Setter
public class DimensionAssetsTerm {

    private List<DimensionInfo> targets;

    private String assetType;

    private Boolean not;

    private List<String> relations;

    public DimensionAssetsTerm not(boolean not) {
        this.not = not;
        return this;
    }

    public DimensionAssetsTerm relation(String relation) {
        if (relations == null) {
            relations = new ArrayList<>();
        }
        relations.add(relation);
        return this;
    }

    public List<Object> toTargetKeys() {
        return targets
            .stream()
            .map(dimension -> DimensionAssetBindingEntity.generateKey(dimension.getType(), dimension.getId()))
            .collect(Collectors.toList());
    }

    public static DimensionAssetsTerm of(List<DimensionInfo> dimensions, String assetType) {
        DimensionAssetsTerm term = new DimensionAssetsTerm();
        term.setTargets(dimensions);
        term.setAssetType(assetType);
        return term;
    }

    public static DimensionAssetsTerm of(List<Dimension> dimensions, String assetType, boolean not) {
        DimensionAssetsTerm term = new DimensionAssetsTerm();
        term.setTargets(dimensions
                            .stream()
                            .map(dimension -> DimensionInfo.of(dimension.getType().getId(), dimension.getId()))
                            .collect(Collectors.toList()));
        term.setNot(not);
        term.setAssetType(assetType);
        return term;
    }

    public static DimensionAssetsTerm of(Term term) {
        Object value = term.getValue();
        if (value instanceof DimensionAssetsTerm) {
            return ((DimensionAssetsTerm) value);
        }
        JSONObject obj;
        if (value instanceof String) {
            obj = JSON.parseObject(String.valueOf(value));
        } else if (value instanceof Map) {
            obj = new JSONObject(((Map) value));
        } else {
            throw new UnsupportedOperationException("error.unsupported_term");
        }
        DimensionAssetsTerm assetsTerm = obj.toJavaObject(DimensionAssetsTerm.class).validate();
        if (assetsTerm.not == null) {
            assetsTerm.setNot(term.getOptions().contains("not"));
        }
        return assetsTerm;
    }

    public DimensionAssetsTerm validate() {
        Assert.notEmpty(targets, "validation.target_can_not_be_empty");
        Assert.hasText(assetType, "validation.type_can_not_be_empty");
        return this;
    }

}
